# -*- coding: utf-8 -*-
class           Lexer

  def           initialize(file1, file2)
    @file_unistd = file1
    @file_syscall = file2
  end

  def           epur_str(str)

    i = 0
    string = ""

    j = 0

    while (str[i])
      if (str[i] == " " || str[i] == "\t")
        if (i != 0)
          string += " "
        end
        while (str[i] == " " || str[i] == "\t")
          i += 1
        end
      else
        string += str[i]
        i += 1
      end
    end
    return string
  end

  def           hash_unistd(progressDialog)
    tab_sys = []
    count = 0
    len = @file_unistd.size
    #for each line of the file unistd
    @file_unistd.each_line { |line|
      tab = line.split(" ")
      if (tab.size == 3 && tab[1].include?("__NR_"))
        #split the string and create a hash with the name of the syscall and its id
        tab_sys << {:syscall => tab[1][5..tab[1].size], :id => tab[2]}
      end
      #to have a progressbar from 0 to 99%
      progressDialog.setValue(((count * 100.0) / len).to_i)
      count += line.size
    }
    return tab_sys
  end

  def           hash_syscall(progressDialog)
    tab = @file_syscall.readlines
    len = @file_syscall.size
    count = 0
    str = ""
    tab_sys = []
    prev = 0

    progressDialog.setValue(0)
    tab.each { |line|
      #get the line without \n
      line = line.chomp
      #check the line
      if (line.include?("asmlinkage long sys_") && !line.include?("asmlinkage long sys_old") && line.index("asmlinkage long sys_") == 0)
        prev = 1
        #check if the prototype is ok
        if (line.rindex(';'))
          if (line[20...line.index('(')] == "read")
            tab_sys << { :syscall => "read", :args => "int fd, void *buf, int count" }
          elsif
            tab_sys << { :syscall => line[20...line.index('(')], :args => line[(line.index('(') + 1)..(line.size - 3)].gsub(" __user", "") }
          end
          str = ""
          prev = 0
        else
          str = line
        end
      else
        #si la ligne ne commence pas par asmlinkage (= peut etre deuxieme ligne d'argument)
        if (prev == 1)
          prev = 0
          #add la ligne d'arg
          str += epur_str(line)
          #si finit par ";" = prototype terminé
          if (!str.rindex(';'))
            prev = 1
          else
            if (str[20...str.index('(')] == "read")
              tab_sys << { :syscall => "read", :args => "int fd, void *buf, int count" }
            elsif
              tab_sys << {:syscall => str[20...str.index('(')], :args => str[(str.index('(') + 1)..(str.size - 4)].gsub(" __user", "")}
            end
          end
        end
      end
      progressDialog.setValue(((count * 100.0) / len).to_i)
      count += line.size
    }
    tab_sys.each { |x|
      if (x[:syscall].include?("mmap") && x[:syscall] == "mmap_pgoff")
        x[:syscall] = "mmap"
        x[:args] = "void *addr, size_t length, int prot, int flags, int fd, off_t offset"
      end
    }
    tab_sys << {:syscall => "create_module", :args => "void"}
    tab_sys << {:syscall => "get_kernel_syms", :args => "void"}
    tab_sys << {:syscall => "set_thread_area", :args => "void"}
    tab_sys << {:syscall => "iopl", :args => "void"}
    tab_sys << {:syscall => "security", :args => "void"}
    tab_sys << {:syscall => "query_module", :args => "void"}
    tab_sys << {:syscall => "clone", :args => "void"}
    tab_sys << {:syscall => "umount2", :args => "void"}
    tab_sys << {:syscall => "arch_prctl", :args => "void"}
    tab_sys << {:syscall => "fork", :args => "void"}
    tab_sys << {:syscall => "rt_sigaction", :args => "int arg, void *ptr1, void *ptr2"}
    tab_sys << {:syscall => "vfork", :args => "void"}
    tab_sys << {:syscall => "rt_sigsuspend", :args => "void"}
    tab_sys << {:syscall => "sigaltstack", :args => "void"}
    tab_sys << {:syscall => "modify_ldt", :args => "void"}
    tab_sys << {:syscall => "_sysctl", :args => "void"}
    tab_sys << {:syscall => "nfsservctl", :args => "void"}
    tab_sys << {:syscall => "getpmsg", :args => "void"}
    tab_sys << {:syscall => "putpmsg", :args => "void"}
    tab_sys << {:syscall => "afs_syscall", :args => "void"}
    tab_sys << {:syscall => "tuxcall", :args => "void"}
    tab_sys << {:syscall => "get_thread_area", :args => "void"}
    tab_sys << {:syscall => "epoll_ctl_old", :args => "void"}
    tab_sys << {:syscall => "epoll_wait_old", :args => "void"}
    tab_sys << {:syscall => "vserver", :args => "void"}
    tab_sys << {:syscall => "execve", :args => "void"}
    tab_sys << {:syscall => "rt_sigreturn", :args => "unsigned long __unused"}
    progressDialog.setValue(100)
    return tab_sys
  end

end
